package com.vdong.trade.order.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.vdong.interactive.course.facade.PeddleGoodsFacadeService;
import com.vdong.member.account.facade.AccountPeddleUserFacadeService;
import com.vdong.member.account.facade.AccountSystemUserFacadeService;
import com.vdong.rocketmq.TopicEnum;
import com.vdong.rocketmq.producer.processor.MQProducerSendMsgProcessor;
import com.vdong.rocketmq.producer.processor.MQSendResult;
import com.vdong.trade.order.common.contract.TableContract;
import com.vdong.trade.order.common.exception.ProcessException;
import com.vdong.trade.order.common.foundation.FoundationCRUDOperation;
import com.vdong.trade.order.common.rocketMq.TagConstants;
import com.vdong.trade.order.entity.dto.param.*;
import com.vdong.trade.order.entity.dto.result.*;
import com.vdong.trade.order.entity.mo.OrderDisbRedundancyMO;
import com.vdong.trade.order.entity.mo.OrderDisbSnapshotMO;
import com.vdong.trade.order.entity.mo.OrderMO;
import com.vdong.trade.order.entity.mo.TradingParamMO;
import com.vdong.trade.order.repository.OrderDisbRedundancyMORepository;
import com.vdong.trade.order.repository.OrderDisbSnapshotMORepository;
import com.vdong.trade.order.repository.OrderMORepository;
import com.vdong.trade.order.service.DisbOrderService;
import com.vdong.trade.trading.facade.AmountFacade;
import com.vdong.trade.trading.facade.TradingFacade;
import com.vdong.trade.trading.facade.TransactionPayFacade;
import com.vdong.trade.trading.facade.enums.PayChannelEnum;
import com.vdong.trade.trading.facade.enums.UserTypeEnum;
import com.vdong.trade.trading.facade.enums.WechatPayEnums;
import lombok.extern.slf4j.Slf4j;
import org.lamb.framework.common.guid.LambGUIDFactory;
import org.lamb.framework.common.remote.FacadeResult;
import org.lamb.framework.common.userDTO.AppUserMainDTO;
import org.lamb.framework.common.userDTO.PeddleUserDTO;
import org.lamb.framework.common.util.BigDecimalUtil;
import org.lamb.framework.common.util.FacadeResultUtils;
import org.lamb.framework.common.util.StringUtil;
import org.lamb.framework.core.annotation.LambValid;
import org.lamb.framework.core.security.LambPrincipalFactoryContainer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Optional;

import static com.vdong.trade.order.common.enums.ProcessExceptionEnum.*;

/**
 * @description: 知识付费订单流程
 * @author: Mr.WangGang
 * @create: 2018-11-23 上午 11:40
 **/
@Service
@Slf4j
@com.alibaba.dubbo.config.annotation.Service
public class DisbOrderServiceImpl extends FoundationCRUDOperation implements DisbOrderService {

    @Resource
    private LambGUIDFactory lambGuidFactory;

    @Resource
    private OrderDisbRedundancyMORepository orderDisbRedundancyMORepository;

    @Resource
    private OrderDisbSnapshotMORepository orderDisbSnapshotMORepository;

    @Resource
    private OrderMORepository orderMORepository;

    @Reference
    private TradingFacade tradingFacade;

    @Reference
    private AmountFacade amountFacade;

    @Reference
    private PeddleGoodsFacadeService peddleGoodsFacadeService;

    @Reference
    private AccountPeddleUserFacadeService accountPeddleUserFacadeService;

    @Reference
    private AccountSystemUserFacadeService accountSystemUserFacadeService;

    @Reference
    private TransactionPayFacade transactionPayFacade;

    @Resource
    private MQProducerSendMsgProcessor producerSendMsgProcessor;

    @Override
    @LambValid
    public <T extends DisbOrderCreateParamDTO> DisbOrderCreateResultDTO create(@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        log.info("create,入参为:[{}]", JSON.toJSONString(param));
        AppUserMainDTO appUser = LambPrincipalFactoryContainer.getAppUser();
        log.info("获取到的登陆对象为：[{}]", JSON.toJSONString(appUser));
        if (StringUtil.hasBlank(appUser)) throw new ProcessException(EB00000003);
        //根据商品id获取商品信息
        String basePeddleGoodsDetail = peddleGoodsFacadeService.getBasePeddleGoodsDetail
                (JSON.toJSONString(PeddleUserParamDTO.builder().peddleGoodsId(param.getData().getProductKey()).build()));
        if (StringUtil.hasBlank(basePeddleGoodsDetail)) throw new ProcessException(EB00000003);
        BasePeddleGoodsDTO disbProduct = FacadeResultUtils.stringToFacadeBean(basePeddleGoodsDetail,
                BasePeddleGoodsDTO.class).getData();
        log.info("获取到的商品BasePeddleGoodsDTO为:[{}]", disbProduct);
        log.info("====[{}],[{}]", disbProduct.getOpenState(), disbProduct.getDeleted());
        if (disbProduct.getOpenState() == 0 || disbProduct.getDeleted()) throw new ProcessException(EB00000003);

        //根据推客id获取推客
        String peddleUserDetail = accountPeddleUserFacadeService.getPeddleUserDetail
                (JSON.toJSONString(PeddleUserParamDTO.builder().id(param.getData().getPusherKey()).build()));
        if (StringUtil.hasBlank(peddleUserDetail)) throw new ProcessException(EB00000002);
        PeddleUserDTO pusherUser = FacadeResultUtils.stringToFacadeBean(peddleUserDetail, PeddleUserDTO.class).getData();
        log.info("获取到的推客pusherUser为:[{}]", pusherUser);
        //获取公司
        String peddleSaasSysUser = accountSystemUserFacadeService.getPeddleSaasSysUser();
        if (StringUtil.hasBlank(peddleSaasSysUser)) throw new ProcessException(EB00000012);
        AccountPeddleSaasSysUserInfoDTO sysUser = FacadeResultUtils.
                stringToFacadeBean(peddleSaasSysUser, AccountPeddleSaasSysUserInfoDTO.class).getData();
        if (StringUtil.hasBlank(sysUser)) {
            AccountPeddleSaasSysUserInfoDTO dto = new AccountPeddleSaasSysUserInfoDTO();
            dto.setSysUserId("600000001");
            dto.setPlatformId("600000001");
            dto.setSysUserName("18924011511");
            sysUser = dto;
        }
        log.info("获取到获取公司peddleSaasSysUser为:[{}]", sysUser);
        //获取商户
        String merchantUser = accountSystemUserFacadeService.getAccountSystemPeddleUserInfoBySysUserId
                (JSON.toJSONString(ChannelCurveParamDTO.builder().sysUserId(disbProduct.getSysUserId())
                        .userType(UserTypeEnum.MERCHANT.getValue().toString()).build()));
        if (StringUtil.hasBlank(merchantUser)) throw new ProcessException(EB00000012);
        MerchantSaasSysUserInfoDTO merchantDTO = FacadeResultUtils.
                stringToFacadeBean(merchantUser, MerchantSaasSysUserInfoDTO.class).getData();
        log.info("获取获取商户merchantUser为:[{}]", merchantDTO);
        String guid = lambGuidFactory.GUID();
        boolean flag = saveOrderIsSuccess(guid, pusherUser, disbProduct, appUser, param.getTarget(), sysUser, merchantDTO);
        if (!flag) throw new ProcessException(EB00000004);

        log.info("创建订单成功================,订单号为:[{}]", guid);
        return DisbOrderCreateResultDTO.builder().orderNo(guid).body(disbProduct.getGoodsName()).build();
    }

    @Transactional
    protected boolean saveOrderIsSuccess(String guid, PeddleUserDTO pusherUser, BasePeddleGoodsDTO disbProduct,
                                         AppUserMainDTO appUser, String target, AccountPeddleSaasSysUserInfoDTO sysUser,
                                         MerchantSaasSysUserInfoDTO merchantDTO) {
        OrderMO orderMO = OrderMO.builder()
                .buyerKey(appUser.getId())
                .productKey(disbProduct.getPeddleGoodsId())
                .orderModel(TableContract.Order.OrderModel.DISB)
                .orderNo(guid)
                .orderStatus(target)
                .orderType(TableContract.Order.OrderType.DisbOrderType.PROMOTION)
                .status(TableContract.Order.status.EFFECTIVE)
                .orderAmount(disbProduct.getPrice())
                .createTime(new Date())
                .updateTime(new Date())
                .disbProductMirror(JSON.toJSONString(disbProduct))
                .build();

        int orderSave = orderMORepository.insertOrder(orderMO);
        if (orderSave < 1) throw new ProcessException(EB00000004);

        log.info("获取到的商品价格:[{}]", disbProduct.getPrice());
        //商户收益比例
        BigDecimal merchantPercent = BigDecimalUtil.sub(String.valueOf(BigDecimalUtil.sub("100", String.valueOf(disbProduct.
                getPlatformProfitRatio()))), String.valueOf(disbProduct.getPromoterProfitRatio()));
        log.info("获取到的商户收益比例:[{}]", merchantPercent);
        //商户收益
        BigDecimal merchant = BigDecimalUtil.round(String.valueOf(BigDecimalUtil.div(String.valueOf(BigDecimalUtil
                .mul(String.valueOf(disbProduct.getPrice()), String.valueOf(merchantPercent))), "100")), 2);

        log.info("获取到的商户收益:[{}]", merchant);
        //推客收益
        BigDecimal push = BigDecimalUtil.round(String.valueOf(BigDecimalUtil.div(String.
                valueOf(BigDecimalUtil.mul(String.valueOf(disbProduct.getPrice()),
                        String.valueOf(disbProduct.getPromoterProfitRatio()))), "100")), 2);
        log.info("获取到的推客收益:[{}]", push);
        //公司收益
        BigDecimal plat = BigDecimalUtil.sub(String.valueOf(BigDecimalUtil.sub(String.valueOf(disbProduct
                .getPrice()), String.valueOf(merchant))), String.valueOf(push));
        if (plat.compareTo(BigDecimal.ZERO) < 0) {
            plat = BigDecimal.ZERO;
        }
        log.info("获取到的公司收益:[{}]", plat);

        OrderDisbSnapshotMO orderDisbSnapshotMO = OrderDisbSnapshotMO.builder()
                .orderId(orderMO.getId())
                .pusherKey(pusherUser.getId())
                .merchantKey(disbProduct.getSysUserId())
                .companyKey(Long.valueOf(sysUser.getSysUserId()))
                .productDistributionAmount(merchant)
                .platformExtractionRate(new BigDecimal(disbProduct.getPlatformProfitRatio()))
                .platformAnticipatedIncomeAmount(plat)
                .pusherCommissionRate(new BigDecimal(disbProduct.getPromoterProfitRatio()))
                .pusherAnticipatedIncomeAmount(push)
                .createTime(new Date())
                .updateTime(new Date())
                .build();
        int snapSave = orderDisbSnapshotMORepository.insertOrderDisbSnapshot(orderDisbSnapshotMO);
        if (snapSave < 1) throw new ProcessException(EB00000004);

        OrderDisbRedundancyMO orderDisbRedundancyMO = OrderDisbRedundancyMO.builder()
                .orderId(orderMO.getId())
                .productName(disbProduct.getGoodsName())
                .productDescribe(disbProduct.getGoodsIntroduction())
                .productType("1")
                .storeId(disbProduct.getSysUserId())
                .companyName(sysUser.getSysUserName())
                .merchantName(merchantDTO.getSysUserName())
                .buyerName(appUser.getNickName())
                .buyerWxName(appUser.getNickName())
                .phone("-1")
                .pusherName(pusherUser.getNickName())
                .pusherWxName(pusherUser.getNickName())
                .productClassify(String.valueOf(disbProduct.getClassifyType()))
                .createTime(new Date())
                .updateTime(new Date())
                .build();
        int redundancyRow = orderDisbRedundancyMORepository.insertOrderDisbRedundancy(orderDisbRedundancyMO);
        if (redundancyRow < 1) throw new ProcessException(EB00000004);
        return true;
    }

  /*  @Override
    @LambValid
    public <T extends DisbOrderApplyPayParamDTO> DisbOrderApplyPayResultDTO applyPay(@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        log.info("applyPay,入参为:[{}]", JSON.toJSONString(param));
        OrderMO orderMO = orderMORepository.selectOrderByEntity(OrderMO.builder().orderNo(param.getData().getOrderNo()).build());
        orderMO.setOrderStatus(TableContract.Order.OrderStatus.DisbOrderStatus.UNPAID);
        int row = orderMORepository.updateOrderById(orderMO);
        if (row < 1) {
            throw new ProcessException(EB00000009);
        }
        return DisbOrderApplyPayResultDTO.builder().orderAmount(String.valueOf(orderMO.getOrderAmount())).build();
        // 调支付服务  PARAM 支付通道  支付param  orderNo

       String payNo = payService.execute(param.getData().getOrderNo(), param.getData().getPayChannel());
        return DisbOrderApplyPayResultDTO.builder().payNo(payNo);

//       return payNo;
    }*/

    @Override
    @LambValid
    public <T extends DisbOrderPayParamDTO> DisbOrderPayResultDTO pay(@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        log.info("pay,入参为:[{}]", JSON.toJSONString(param));
        OrderMO orderMO = orderMORepository.selectOrderByEntity(OrderMO.builder()
                .orderNo(param.getData().getOrderNo()).build());
        if (StringUtil.hasBlank(orderMO)) throw new ProcessException(EB00000000);
        if (StringUtil.hasBlank(param.getData().getKpayOrderNo())) param.getData().setKpayOrderNo("-1");
        PaymentRequestDTO body = PaymentRequestDTO.builder()
                .totalFee(BigDecimalUtil.mul(String.valueOf(orderMO.getOrderAmount()), "100").longValue())
                .spbillCreateIp("127.0.0.1")
                .payChannel(PayChannelEnum.WECHAT_PAY.getCode())
                .orderType(WechatPayEnums.OrderTypeEnum.USER_PAY.getType())
                .tradeType(param.getData().getTradeType())
                .openid(param.getData().getOpenId())
                .orderNo(param.getData().getOrderNo())
                .body(param.getData().getBody())
                .kpayOrderNo(param.getData().getKpayOrderNo()).build();
        log.info("获取到的body为：[{}]", JSON.toJSONString(body));
        try {
            FacadeResult<String> stringFacadeResult = transactionPayFacade.execPay(JSON.toJSONString(body));
            log.info("请求支付返回的参数是：[{}]", JSON.toJSONString(stringFacadeResult));
            if (stringFacadeResult.isSuccess()) {
                orderMO.setOrderStatus(TableContract.Order.OrderStatus.DisbOrderStatus.INPAID);
                int row = orderMORepository.updateOrderById(orderMO);
                if (row < 1) throw new ProcessException(EB00000009);
                log.info("请求支付成功===============");
                return StringUtil.stringToBean(stringFacadeResult.getData(), DisbOrderPayResultDTO.class);
            } else {
                log.info(stringFacadeResult.getErrorMsg());
            }
            throw new ProcessException(EB00000010);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    @LambValid
    @Transactional
    public <T extends DisbOrderPayDoneParamDTO> DisbOrderPayDoneResultDTO payDone
            (@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) throws Exception {
        log.info("payDone,入参为:[{}]", JSON.toJSONString(param));
        if (!param.getData().getCode()) throw new ProcessException(EB00000006);
        if (StringUtil.hasBlank(param.getData().getKpayOrderNo())) param.getData().setKpayOrderNo("-1");
        OrderMO orderMO = orderMORepository.selectOrderByEntity(OrderMO.builder()
                .orderNo(param.getData().getOrderNo())
                .orderStatus(TableContract.Order.OrderStatus.DisbOrderStatus.INPAID).build());
        Optional.ofNullable(orderMO).orElseThrow(() -> new ProcessException(EB00000004));
        //更新订单
        orderMO.setOrderStatus(TableContract.Order.OrderStatus.DisbOrderStatus.PAID);
        int orderRow = orderMORepository.updateOrderById(orderMO);
        if (orderRow < 1) throw new ProcessException(EB00000009);
        log.info("更新订单成功=================");
        MQSendResult mqSendResult = producerSendMsgProcessor.send(TopicEnum.OrderTopic,
                TagConstants.OrderTopic.OrderPayDone, param.getData().getKpayOrderNo());
        //回调支付成功调用 交易服务 交易服务插入3笔交易流水
        TradingParamMO tradingParamMO = orderMORepository.selectTradingParam(orderMO.getOrderNo());
        if (StringUtil.hasBlank(tradingParamMO)) throw new ProcessException(EB00000011);
        tradingParamMO.setWechatDataId(param.getData().getWechatDataId());
        FacadeResult<FacadeResult> result = FacadeResultUtils.stringToFacadeBean
                (tradingFacade.insertThreeTrading(JSON.toJSONString(tradingParamMO)), FacadeResult.class);
        if (!result.isSuccess()) throw new ProcessException(EB00000004);
        log.info("交易服务插入3笔交易流水成功=================");
        //账户服务 资金操作 订单交易成功 增加未结算金额
        FacadeResult<FacadeResult> amountResult = FacadeResultUtils.stringToFacadeBean
                (amountFacade.updateUserAmount(JSON.toJSONString(tradingParamMO)), FacadeResult.class);
        if (!amountResult.isSuccess()) throw new ProcessException(EB00000004);
        log.info("更新资金成功===================");
        //推客升级
        try {
            String pusherMoney = tradingFacade.pusherEarnings(JSON.toJSONString(ChannelCurveParamDTO.builder()
                    .userId(String.valueOf(tradingParamMO.getPusherId()))
                    .userType(UserTypeEnum.PUSHER.getValue().toString()).build()));
            PusherEarningResultDTO dto = new PusherEarningResultDTO();
            if (!StringUtil.hasBlank(pusherMoney)) {
                dto = FacadeResultUtils.stringToFacadeBean(pusherMoney,
                        PusherEarningResultDTO.class).getData();
            } else {
                dto = PusherEarningResultDTO.builder().totalEarning(BigDecimal.ZERO).build();
            }
            log.info("请求推客升级==================:[{}]", JSON.toJSONString(ChannelCurveParamDTO.builder()
                    .peddleUserId(tradingParamMO.getPusherId())
                    .totalProfit(dto.getTotalEarning()).build()));
            String s = accountPeddleUserFacadeService.peddleUserLevelUpdate
                    (JSON.toJSONString(ChannelCurveParamDTO.builder()
                            .peddleUserId(tradingParamMO.getPusherId())
                            .totalProfit(dto.getTotalEarning()).build()));
        } catch (Exception e) {
            log.info("请求推客升级失败，异常为：[{}]", e);
            return DisbOrderPayDoneResultDTO.builder().isSuccess(true).build();
        }
        log.info("支付回调成功==================");
        return DisbOrderPayDoneResultDTO.builder().isSuccess(true).build();
    }

    @Override
    @LambValid
    public <T extends DisbOrderApplyRefundParamDTO> DisbOrderApplyRefundResultDTO applyRefund
            (@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        //退款
        return null;
    }

    @Override
    @LambValid
    public <T extends DisbOrderRefundParamDTO> DisbOrderRefundResultDTO refund
            (@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        //进行退款
        return null;
    }

    @Override
    @LambValid
    public <T extends DisbOrderRefundDoneParamDTO> DisbOrderRefundDoneResultDTO refundDone
            (@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        //
        return null;
    }

    @Override
    @LambValid
    public <T extends DisbOrderCancelParamDTO> DisbOrderCancelResultDTO cancel
            (@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        log.info("cancel,入参为:[{}]", JSON.toJSONString(param));
        OrderMO orderMO = orderMORepository.selectOrderByEntity(OrderMO.builder()
                .orderNo(param.getData().getOrderNo())
                .orderStatus(TableContract.Order.OrderStatus.DisbOrderStatus.INPAID).build());
        Optional.ofNullable(orderMO).orElseThrow(() -> new ProcessException(EB00000004));
        orderMO.setOrderStatus(TableContract.Order.OrderStatus.DisbOrderStatus.CANCEL);
        int row = orderMORepository.updateOrderById(orderMO);
        if (row < 1) {
            throw new ProcessException(EB00000009);
        }
        return DisbOrderCancelResultDTO.builder().orderNo(param.getData().getOrderNo()).success(true).build();
    }

    @Override
    @LambValid
    public <T extends DisbOrderApplySettlementParamDTO> DisbOrderApplySettlementResultDTO applySettlement
            (@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        return null;
    }

    @Override
    @LambValid
    public <T extends DisbOrderSettlementParamDTO> DisbOrderSettlementResultDTO settlement
            (@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        return null;
    }

    @Override
    @LambValid
    public <T extends DisbOrderSettlementDoneParamDTO> DisbOrderSettlementDoneResultDTO settlementDone
            (@Valid @NotNull OrderStateMachineTransitionParamDTO<T> param) {
        return null;
    }

}
